package com.coke.spring.security.config;

/**
 * @author cwm
 * @Description TODO
 * @date 2021/8/26 上午10:29
 * @Version 1.0
 */

import com.coke.spring.security.filter.IpAuthenticationProcessingFilter;
import com.coke.spring.security.filter.MObelAuthenticationProcessingFilter;
import com.coke.spring.security.provider.IpAuthenticationProvider;
import com.coke.spring.security.provider.MobelAuthenticationProvider;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

@Configuration
/**
 * @EnableWebSecurity 是一个复合注解 激活了
 * {@link org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration}
 *      在这个配置类中，有一个非常重要的Bean被注册了 springSecurityFilterChain
 *      @Bean(name = AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME)
 *     public Filter springSecurityFilterChain() throws Exception {
 *     	...
 *     }
 * {@link org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration}
 * AuthenticationConfiguration的主要任务，便是负责生成全局的身份认证管理者AuthenticationManager
 * AuthenticationManager便是最核心的身份认证管理器
 *
 *
 */
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    //ip认证者配置
    @Bean
    IpAuthenticationProvider ipAuthenticationProvider() {
        return new IpAuthenticationProvider();
    }
    //手机认证者配置
    @Bean
    MobelAuthenticationProvider mobelAuthenticationProvider() {
        return new MobelAuthenticationProvider();
    }

    //配置封装ipAuthenticationToken的过滤器
    IpAuthenticationProcessingFilter ipAuthenticationProcessingFilter(AuthenticationManager authenticationManager) {
        IpAuthenticationProcessingFilter ipAuthenticationProcessingFilter = new IpAuthenticationProcessingFilter();
        //为过滤器添加认证器
        ipAuthenticationProcessingFilter.setAuthenticationManager(authenticationManager);
        //重写认证失败时的跳转页面
        ipAuthenticationProcessingFilter.setAuthenticationFailureHandler(new SimpleUrlAuthenticationFailureHandler("/ipLogin?error"));
        return ipAuthenticationProcessingFilter;
    }

    MObelAuthenticationProcessingFilter mObelAuthenticationProcessingFilter(AuthenticationManager authenticationManager){
        MObelAuthenticationProcessingFilter mObelAuthenticationProcessingFilter = new MObelAuthenticationProcessingFilter();
        mObelAuthenticationProcessingFilter.setAuthenticationManager(authenticationManager);
        return mObelAuthenticationProcessingFilter;
    }

    @Bean
    public PasswordEncoder passwordEncoder(){
//        return NoOpPasswordEncoder.getInstance();
        return new BCryptPasswordEncoder();
    }

    //配置登录端点
    @Bean
    LoginUrlAuthenticationEntryPoint loginUrlAuthenticationEntryPoint(){
        LoginUrlAuthenticationEntryPoint loginUrlAuthenticationEntryPoint = new LoginUrlAuthenticationEntryPoint
                ("/ipLogin");
        return loginUrlAuthenticationEntryPoint;
    }
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                //访问根和home不需要认证授权
                .antMatchers("/","/home").permitAll()
                .antMatchers("/ipLogin").permitAll()
                .anyRequest().authenticated()
                .and()
                .formLogin()
                //指定登录页面
                .loginPage("/login")
                //访问logine不需要认证授权
                .permitAll()
                .and()
                //退出不需要授权
                .logout().permitAll()
                .and()
                .exceptionHandling()
                .accessDeniedPage("/ipLogin")
                .authenticationEntryPoint(loginUrlAuthenticationEntryPoint());
        //注册IpAuthenticationProcessingFilter  注意放置的顺序 这很关键
        http.addFilterBefore(ipAuthenticationProcessingFilter(authenticationManager()), UsernamePasswordAuthenticationFilter.class);
        http.addFilterBefore(mObelAuthenticationProcessingFilter(authenticationManager()),IpAuthenticationProcessingFilter.class);
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
                //内存方式配置用户
                .withUser("admin").password("$2a$10$xDuIerNkKxjSSpEtXCdin.6bvkxndPjahZ52Kl3igOq.VP1BHjwqO").roles("USER");
        auth.authenticationProvider(ipAuthenticationProvider());
        auth.authenticationProvider(mobelAuthenticationProvider());
    }
}
